﻿using System;
using System.Configuration;
using System.Web;
using System.Collections.Generic;

using Model;
using BLL.WWW_WWW.Wiki;
using Model.WWW_WWW.Wiki;

namespace BLF.WWW_WWW.Wiki
{
    /// <summary>
    /// Content 的摘要说明
    /// </summary>
    public static class Content
    {

        // Contains cached Pages
        private static Dictionary<PageInfo, PageContent> cache;
        private static Dictionary<PageInfo, string> formattedCache;
        private static List<PageInfo> addedKeys;
        private static WikiSystem wikiSytem = new WikiSystem();

        // Contains cached text such as header, sidebar...
        private static Dictionary<string, string> pseudoCache = new Dictionary<string, string>();

        /// <summary>
        /// Gets or sets the Pseudo Cache object.
        /// </summary>
        public static Dictionary<string, string> PseudoCache
        {
            get { return pseudoCache; }
            set { pseudoCache = value; }
        }

        /// <summary>
        /// Reads the Content of a Page.
        /// </summary>
        /// <param name="pageInfo">The Page.</param>
        /// <param name="cached">Specifies whether the page has to be cached or not.</param>
        /// <returns>The Page Content.</returns>
        public static PageContent GetPageContent(PageInfo pageInfo, bool cached)
        {
            if (cache == null)
            {
                cache = new Dictionary<PageInfo, PageContent>(Settings.CacheSize);
                formattedCache = new Dictionary<PageInfo, string>(Settings.CacheSize);
                addedKeys = new List<PageInfo>(Settings.CacheSize);
            }

            PageContent result;
            if (!cache.TryGetValue(pageInfo, out result))
            {
                result = wikiSytem.GetContent(pageInfo);
                if (cached && !pageInfo.NonCached && !Settings.DisableCache)
                {
                    cache.Add(pageInfo, result);
                    addedKeys.Add(pageInfo);
                }
                if (cache.Count > Settings.CacheSize)
                {
                    CutCache();
                }
            }
            else
            {
                // This way the least-recently used Pages stay at the beginning of the array,
                // while the most-recently used Pages stay at the end
                addedKeys.Remove(pageInfo);
                addedKeys.Add(pageInfo);
            }

            // result should NEVER be null, so if it happens throw exception
            if (result == null) throw new Exception("Cannot extract Page Content.");

            return result;
        }

        /// <summary>
        /// Gets the formatted Page Content, properly handling content caching and the Formatting Pipeline.
        /// </summary>
        /// <param name="page">The Page to get the formatted Content of.</param>
        /// <param name="cached">Specifies whether the formatted content has to be cached or not.</param>
        /// <returns>The Formatted Content.</returns>
        public static string GetFormattedPageContent(PageInfo page, bool cached)
        {
            string content;
            if (!formattedCache.TryGetValue(page, out content))
            {
                PageContent pg = GetPageContent(page, cached);
                PageInfo[] linkedPages;
                content = FormattingPipeline.FormatWithPhase1And2(pg.Content, page, out linkedPages);
                pg.LinkedPages = linkedPages;
                if (cached && !page.NonCached && !Settings.DisableCache) formattedCache.Add(page, content);
            }
            return FormattingPipeline.FormatWithPhase3(content, page);
        }

        /// <summary>
        /// Invalidates the cached Content of a Page.
        /// </summary>
        /// <param name="pageInfo">The Page to invalidate the cached content of.</param>
        public static void Invalidate(PageInfo pageInfo)
        {
            if (cache == null) return;
            cache.Remove(pageInfo);
            formattedCache.Remove(pageInfo);
            addedKeys.Remove(pageInfo);
        }

        /// <summary>
        /// Invalidates all the cache Contents.
        /// </summary>
        public static void InvalidateAll()
        {
            cache = null;
            formattedCache = null;
            addedKeys = null;
        }

        private static void CutCache()
        {
            // Clear older elements in the cache
            int cutSize = Settings.CacheSize;
            for (int i = 0; i < cutSize; i++)
            {
                if (cache.Count == 0 || cache == null) break;
                cache.Remove(addedKeys[0]);
                formattedCache.Remove(addedKeys[0]);
                addedKeys.Remove(addedKeys[0]);
            }
        }

        /// <summary>
        /// Gets the # of Pages in the Cache.
        /// </summary>
        public static int CacheUsage
        {
            get
            {
                if (cache == null) return 0;
                return cache.Count;
            }
        }

    }
}
